<?php
/**
 * Application class definition
 *   
 * @author Sean Crystal <seancrystal@gmail.com>
 * @package MVP-PHP
 */
require_once 'interfaces/iApplication.php';

/**
 * Initializes the web application, instantiates any necessary objects and
 * hands control off to the requested page
 * @package MVP-PHP
 * @subpackage Application
 */    
class Application implements iApplication
{
	/**
     * Constructor
	 * @param array $settings
	 */  	
	public function __construct($settings)
	{
		$this->settings = $settings;
		$this->injector = new DependencyInjector;
		
		$this->Init();
	}
	
	/**
 	 * Execute any operations necessary before any Request is processed
	 */ 	
	public function Init()
	{	
		$this->SetExceptionHandler();
		$this->SetDependencies();
		//$this->SetErrorHandler();
		$this->InitSession();

	}
	
	/**
     * Pass control to the requested Page
	 * @param Page $page
	 * @param Request $request
	 */   	
	public function Go(Page $page, Request $request)
	{
		// if there is a default renderer defined, pass it into the Page
		$renderer = $this->injector->Bound('iViewRenderer') ? $this->injector->GetInstance('iViewRenderer') : null;

		$page->Display($request, $this->session, $renderer);
	}
	
	/**
     * Custom exception handler. Prints human-readable info to the page. Could 
	 *  also email or log the information to a file.
	 * @param Exception $exception
	 */   	
	public function ExceptionHandler(Exception $exception)
	{
		echo '<b>Uncaught '. get_class($exception) .': '. htmlentities($exception->getMessage()) .'</b><br><pre>';
		echo $this->getDebugBacktrace();
	}
	
	/**
     * Instantiate the application session store
	 */  	
	protected function InitSession()
	{
		$this->session = $this->injector->GetSingleton('iSession');
	}
	
	/**
     * Set a custom error handler to redirect errors as exceptions
     */ 
	protected function SetErrorHandler()
	{
		// this causes problems with Smarty
		set_error_handler(create_function('$x, $y', 'throw new Exception($y, $x);'), E_ALL & ~E_NOTICE);	
	}
	
	/**
     * Set our custom exception handler
	 */ 	
	protected function SetExceptionHandler()
	{
		set_exception_handler(array(&$this, 'ExceptionHandler'));
	}
	
	/**
     * Load any dependency bindings defined in the settings
	 */ 	
	protected function SetDependencies()
	{
		if (count($this->settings['bindings']) > 0) {
			foreach ($this->settings['bindings'] as $binding) {
				$this->injector->Bind(
					$binding['abstract'], 
					$binding['concrete'], 
					($binding['singleton'] ? DependencyInjector::SINGLETON : $binding['namespace']));
			}
		}
	}
	
	/**
     * Get a nicely-formatted debug_backtrace()
	 * @return string
	 */  	
	protected function GetDebugBacktrace($NL = "<BR>")
    {
        $dbgTrace = debug_backtrace();
        $dbgMsg .= $NL . "Debug backtrace begin:$NL";
        
        foreach ($dbgTrace as $dbgIndex => $dbgInfo) {
            $dbgMsg .= "\t at $dbgIndex  " . $dbgInfo['file'] . " (line {$dbgInfo['line']}) -> {$dbgInfo['function']}(" . join(",", $dbgInfo['args']).")$NL";
        }
        
        $dbgMsg .= "Debug backtrace end" . $NL;
        
        return $dbgMsg;
    }
	
	/**
     * application settings
	 * @var array
	 */  	
	protected $settings;
	
	/**
     * session store instance
	 * @var iSession
	 */  	
	protected $session;
	
	/**
     * dependency injector instance
	 * @var DependencyInjector
	 */  	
	protected $injector;
}

?>